home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / HS.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  15KB  |  604 lines

  1. /* Interface driver for the DRSI PCPA or the Eagle 8530 boards for the IBM PC
  2.  * connected to a WA4DSY 56kbps modem. Uses polling-loop transfers with
  3.  * interrupts disabled for maximum speed.
  4.  */
  5. #include <stdio.h>
  6. #include <dos.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "iface.h"
  10. #include "hs.h"
  11. #include "8530.h"
  12. #include "ax25.h"
  13. #include "trace.h"
  14. #include "pc.h"
  15. #include "proc.h"
  16.  
  17. static void flushrx __ARGS((int16 data));
  18. static void hdlcparam __ARGS((struct hdlc *hp));
  19. static void hexint __ARGS((struct hdlc *hp));
  20. static void hrxint __ARGS((struct hdlc *hp));
  21. static int hs_stop __ARGS((struct iface *iface));
  22. static int hs_raw __ARGS((struct iface *iface,struct mbuf *bp));
  23. static void hs_tx __ARGS((int unused,void *hp1,void *a));
  24. static void hstxoff __ARGS((struct hdlc *hp));
  25. static void hstxon __ARGS((struct hdlc *hp));
  26. static void htxint __ARGS((struct hdlc *hp));
  27.  
  28. static struct hs Hs[NHS];
  29. static INTERRUPT (*Hshandle[])() = { hs0vec };
  30. static struct hdlc Hdlc[2*NHS];
  31. static int16 Nhs;
  32.  
  33. /* Master interrupt handler for the PC-100 card. All interrupts come
  34.  * here first, then are switched out to the appropriate routine.
  35.  */
  36. void
  37. hsint(dev)
  38. int16 dev;
  39. {
  40.     register char iv;
  41.     int16 hsbase;
  42.     register struct hdlc *hp;
  43.     
  44.     Hs[dev].ints++;
  45.     hsbase = Hs[dev].addr;
  46.  
  47. #ifdef    foo
  48.     outportb(hsbase+4,0x8+0x10);    /* HIT EAGLE INTACK */
  49.     (void)inportb(hsbase+CHANA+CTL,R0);
  50.     outportb(hsbase+4,0x8);        /***/
  51. #endif
  52.  
  53.     /* Read interrupt status from channel A */
  54.     while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
  55.         if(iv & CHARxIP){
  56.             /* Channel A Rcv Interrupt Pending */
  57.             hp = &Hdlc[2*dev];
  58.             hrxint(hp);
  59.         } else if(iv & CHATxIP){
  60.             /* Channel A Transmit Int Pending */
  61.             hp = &Hdlc[2*dev];
  62.             htxint(hp);
  63.         } else if(iv & CHAEXT){
  64.             /* Channel A External Status Int */
  65.             hp = &Hdlc[2*dev];
  66.             hexint(hp);
  67.         } else if(iv & CHBRxIP){
  68.             /* Channel B Rcv Interrupt Pending */
  69.             hp = &Hdlc[(2*dev)+1];
  70.             hrxint(hp);
  71.         } else if(iv & CHBTxIP){
  72.             /* Channel B Transmit Int Pending */
  73.             hp = &Hdlc[(2*dev)+1];
  74.             htxint(hp);
  75.         } else if(iv & CHBEXT){
  76.             /* Channel B External Status Int */
  77.             hp = &Hdlc[(2*dev)+1];
  78.             hexint(hp);
  79.         }
  80.         /* Reset interrupt pending state */
  81.         write_scc(hp->ctl,R0,RES_H_IUS);
  82.         outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  83.         outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  84.     }
  85.     outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  86.     outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  87. }
  88. /* HDLC SIO External/Status interrupts
  89.  * The only one that can happen in this driver is a DCD change
  90.  */
  91. static void
  92. hexint(hp)
  93. register struct hdlc *hp;
  94. {
  95.     struct mbuf *rcvbuf;
  96.     struct phdr *phdr;
  97.     char *cp;
  98.     int cnt,data;
  99.     register int ctl;
  100.  
  101.     ctl = hp->ctl;
  102.     data = hp->data;
  103.     hp->exints++;
  104.  
  105.     /* Allocate a receive buffer */
  106.     if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr))) == NULLBUF){
  107.         /* Alloc failed; refuse to proceed */
  108.         hp->nomem++;
  109.         write_scc(ctl,R0,RES_EXT_INT);
  110.         return;
  111.     }
  112.     /* Allow space for phdr descriptor on front */
  113.     cp = rcvbuf->data + sizeof(struct phdr);
  114.     cnt = 0;
  115.  
  116.     /* Disable DCDIE bit so we can track changes in DCD */
  117.     write_scc(ctl,R15,0);
  118.  
  119.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  120.     flushrx(data);
  121.     while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
  122.         if(cnt > 4){
  123.             /* Good frame */
  124.             hp->good++;
  125.             /* Toss crc */
  126.             rcvbuf->cnt = sizeof(struct phdr) + cnt - 1;
  127.             phdr = (struct phdr *)rcvbuf->data;
  128.             phdr->iface = hp->iface;
  129.             phdr->type = TYPE_AX25;
  130.             enqueue(&Hopper,rcvbuf);
  131.             /* Replenish buffer */
  132.             rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct phdr));
  133.         }
  134.         /* Start new buffer */
  135.         if(rcvbuf == NULLBUF)
  136.             break;    /* alloc failed */
  137.         cp = rcvbuf->data + sizeof(struct phdr);
  138.         cnt = 0;
  139.     }    
  140.     write_scc(ctl,R0,RES_EXT_INT);
  141.     write_scc(ctl,R15,DCDIE);    /* Re-enable DCD */
  142.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  143.  
  144.     /* Get rid of fragmentary buffer */
  145.     free_p(rcvbuf);
  146. }
  147. static void
  148. flushrx(data)
  149. register int16 data;
  150. {
  151.     register int i = 5;
  152.     while(i-- != 0)
  153.         (void)inportb(data);
  154. }
  155. /* HDLC receiver interrupt handler.
  156.  * Not used in this driver
  157.  */
  158. static void
  159. hrxint(hp)
  160. register struct hdlc *hp;
  161. {
  162. }
  163. /* HDLC transmit interrupt service routine
  164.  * Not used in this driver
  165.  */
  166. static void
  167. htxint(hp)
  168. register struct hdlc *hp;
  169. {
  170. }
  171.  
  172. /* (re)Initialize HDLC controller parameters */
  173. static void
  174. hdlcparam(hp)
  175. register struct hdlc *hp;
  176. {
  177.     char i_state;
  178.     register int16 ctl;
  179.  
  180.     /* Initialize 8530 channel for SDLC operation */
  181.     ctl = hp->ctl;
  182.     i_state = dirps();
  183.  
  184. #ifdef    foo
  185.     switch(ctl & 2){
  186.     case CHANA:
  187.         write_scc(ctl,R9,CHRA);    /* Reset channel A */
  188.         break;
  189.     case CHANB:
  190.         write_scc(ctl,R9,CHRB);    /* Reset channel B */
  191.         break;
  192.     }
  193.     pause(1L);    /* Allow plenty of time for resetting */
  194. #endif
  195.  
  196.     /* Deselect interrupts for now */
  197.     write_scc(ctl,R1,0);
  198.     write_scc(ctl,R15,0);
  199.  
  200.     /* X1 clock, SDLC mode, Sync modes enable, parity disable */
  201.     write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
  202.  
  203.     /* CRC preset 1, NRZ encoding, no active on poll, flag idle,
  204.      * flag on underrun, no loop mode, 8 bit sync
  205.      */
  206.     write_scc(ctl,R10,CRCPS|NRZ);
  207.  
  208.     /* 8530 gets both tx and rx clock from modem.
  209.      * TRxC = receive clock, RTxC = transmit clock
  210.      */
  211.     write_scc(ctl,R11,RCTRxCP | TCRTxCP);
  212.  
  213.     /* Note: baud rate generator not used */
  214.  
  215.     /* Null out SDLC start address */
  216.     write_scc(ctl,R6,0);
  217.  
  218.     /* SDLC flag */
  219.     write_scc(ctl,R7,FLAG);
  220.  
  221.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  222.      * RTS off, TxCRC enable
  223.      */
  224.     write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  225.  
  226.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  227.      * no address search, no inhibit sync chars, disable RX. Rx is
  228.      * started only by an actual DCD interrupt
  229.      */
  230.     write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
  231.  
  232.     /* Dummy interrupt vector
  233.      * (This probably isn't necessary)
  234.      */
  235.     write_scc(ctl,R2,0);
  236.  
  237.     /* Enable only the external interrupts (modem interrupts) since
  238.      * polling is used for all actual tx/rx operations
  239.      */
  240.     write_scc(ctl,R1,EXT_INT_ENAB);
  241.  
  242.     /* Enable only DCD interrupts */
  243.     write_scc(ctl,R15,DCDIE);
  244.  
  245.     /* No reset, status low, master int enable, enable lower chain,
  246.      * no vector
  247.      */
  248.     write_scc(ctl,R9,MIE|NV);
  249.  
  250.     restore(i_state);
  251. }
  252. /* Attach a high speed iterface to the system
  253.  * argv[0]: hardware type, must be "hs"
  254.  * argv[1]: I/O address, e.g., "0x380"
  255.  * argv[2]: vector, e.g., "2"
  256.  * argv[3]: mode, must be "ax25"
  257.  * argv[4]: interface label, e.g., "drsi0". 
  258.  * argv[5]: receiver packet buffer size in bytes
  259.  * argv[6]: maximum transmission unit, bytes
  260.  * argv[7]: keyup delay, clock ticks
  261.  * argv[8]: persistence value, 0-255
  262.  */
  263. int
  264. hs_attach(argc,argv,p)
  265. int argc;
  266. char *argv[];
  267. void *p;
  268. {
  269.     register struct iface *if_hsa,*if_hsb;
  270.     struct hdlc *hp;
  271.     int dev;
  272.  
  273.     if(Nhs >= NHS){
  274.         printf("Too many hs controllers\n");
  275.         return -1;
  276.     }
  277.     if(if_lookup(argv[4]) != NULLIF){
  278.         printf("Interface %s already exists\n",argv[4]);
  279.         return -1;
  280.     }
  281.     dev = Nhs++;
  282.  
  283.     /* Initialize hardware-level control structure */
  284.     Hs[dev].addr = htoi(argv[1]);
  285.     Hs[dev].vec = htoi(argv[2]);
  286.  
  287.     /* Save original interrupt vector */
  288.     Hs[dev].save.vec = getirq(Hs[dev].vec);
  289.     /* Set new interrupt vector */
  290.     if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
  291.         printf("IRQ %u out of range\n",Hs[dev].vec);
  292.         Nhs--;
  293.         return -1;
  294.     }
  295.     /* Create interface structures and fill in details */
  296.     if_hsa = (struct iface *)calloc(1,sizeof(struct iface));
  297.     if_hsb = (struct iface *)calloc(1,sizeof(struct iface));
  298.  
  299.     if_hsa->name = strdup(argv[4]);
  300.     if_hsb->name = strdup(argv[4]);
  301.     if_hsb->name[strlen(argv[4]) - 1]++;    /* kludge */
  302.     if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
  303.     if_hsa->dev = 2*dev;
  304.     if_hsb->dev = 2*dev + 1;
  305.     if_hsb->stop = if_hsa->stop = hs_stop;
  306.     if_hsb->output = if_hsa->output = ax_output;
  307.     if_hsb->raw = if_hsa->raw = hs_raw;
  308.  
  309.     if(strcmp(argv[3],"ax25") == 0){
  310.         axarp();
  311.         if(Mycall.call[0] == '\0'){
  312.             printf("set mycall first\n");
  313.             free((char *)if_hsa);
  314.             free((char *)if_hsb);
  315.             return -1;
  316.         }        
  317.         if_hsb->send = if_hsa->send = ax_send;
  318.         if(if_hsb->hwaddr == NULLCHAR)
  319.             if_hsb->hwaddr = malloc(sizeof(Mycall));
  320.         memcpy(if_hsb->hwaddr,(char *)&Mycall,sizeof(Mycall));
  321.     } else {
  322.         printf("Mode %s unknown for interface %s\n",
  323.             argv[3],argv[4]);
  324.         free((char *)if_hsa);
  325.         free((char *)if_hsb);
  326.         return -1;
  327.     }
  328.     if_hsa->next = if_hsb;
  329.     if_hsb->next = Ifaces;
  330.     Ifaces = if_hsa;
  331.  
  332.     write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
  333.     hp = &Hdlc[2*dev+1];
  334.     hp->ctl = Hs[dev].addr + CHANB + CTL;
  335.     hp->data = Hs[dev].addr + CHANB + DATA;
  336.     hp->bufsiz = atoi(argv[5]);
  337.     if(argc > 7)
  338.         hp->txdelay = atol(argv[7]);
  339.     else
  340.         hp->txdelay = 1L;
  341.     if(argc > 8)
  342.         hp->p = atoi(argv[8]);
  343.     else
  344.         hp->p = 64;
  345.     hp->iface = if_hsb;
  346.     hdlcparam(hp);
  347.     newproc("hs_tx",1024,hs_tx,0,hp,NULL);
  348.  
  349.     hp = &Hdlc[2*dev];
  350.     hp->ctl = Hs[dev].addr + CHANA + CTL;
  351.     hp->data = Hs[dev].addr + CHANA + DATA;
  352.     hp->bufsiz = atoi(argv[5]);
  353.     hp->txdelay = Hdlc[2*dev+1].txdelay;
  354.     hp->p = Hdlc[2*dev+1].p;
  355.     hp->iface = if_hsb;
  356.     hp->iface = if_hsa;
  357.     hdlcparam(hp);
  358.     newproc("hs_tx",1024,hs_tx,0,hp,NULL);
  359.  
  360.     outportb(Hs[dev].addr + 4,0x08);    /*EAGLE INT GATE */
  361.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  362.     maskon(Hs[dev].vec);
  363.  
  364.     return 0;
  365. }
  366. static int
  367. hs_stop(iface)
  368. struct iface *iface;
  369. {
  370.     int16 dev;
  371.  
  372.     dev = iface->dev;
  373.     if(dev & 1)
  374.         return -1;    /* Valid only for the first device */
  375.     dev >>= 1;    /* Convert back into hs number */
  376.     /* Turn off interrupts */
  377.     maskoff(Hs[dev].vec);
  378.  
  379.     /* Restore original interrupt vector */
  380.     setirq(Hs[dev].vec,Hs[dev].save.vec);
  381.  
  382.     /* Force hardware reset */
  383.     write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
  384.     return 0;
  385. }
  386. /* Send raw packet */
  387. static int
  388. hs_raw(iface,bp)
  389. struct iface *iface;
  390. struct mbuf *bp;
  391. {
  392.  
  393.     struct hdlc *hp;
  394.  
  395.     dump(iface,IF_TRACE_OUT,TYPE_AX25,bp);
  396.     hp = &Hdlc[iface->dev];
  397.     hp->txpkts++;
  398.     enqueue(&hp->txq,bp);    /* Put on queue for hs_tx process */
  399.     return 0;
  400. }
  401.  
  402. /* High speed transmit process */
  403. void
  404. hs_tx(unused,hp1,a)
  405. int unused;
  406. void *hp1;
  407. void *a;    /* Unused */
  408. {
  409.     struct mbuf *bp;
  410.     register int16 cnt;
  411.     register char *cp;
  412.     char *buffer;
  413.     int16 ctl,data;
  414.     int txon = 0;    /* Transmitter on/off state */
  415.     struct hdlc *hp;
  416.  
  417.     hp = (struct hdlc *)hp1;
  418.     ctl = hp->ctl;
  419.     data = hp->data;
  420.  
  421.     for(;;){
  422.         /* Wait for work */
  423.         while(hp->txq == NULLBUF){
  424.             if(txon){
  425.                 /* No more frames, shut down tx */
  426.                 hstxoff(hp);
  427.                 txon = 0;
  428.             }
  429.             pwait(&hp->txq);
  430.         }
  431.         bp = dequeue(&hp->txq);
  432.         /* Copy to new buffer for speed */
  433.         cnt = len_mbuf(bp);
  434.         if((cp = buffer = malloc(cnt)) == NULLCHAR){
  435.             hp->nomem++;
  436.             free_p(bp);
  437.             continue;
  438.         }
  439.         pullup(&bp,cp,cnt);
  440.         /* Turn transmitter on if necessary */
  441.         if(!txon){
  442.             hstxon(hp);
  443.             txon = 1;
  444.         }
  445.         /* Initialize transmitter CRC */
  446.         write_scc(ctl,R0,RES_Tx_CRC);
  447.         for(;;){
  448.             /* Wait for the transmitter to become ready */
  449.             while(!(inportb(ctl) & Tx_BUF_EMP))
  450.                 ;
  451.             if(cnt-- == 0)
  452.                 break;
  453.             outportb(data,*cp++); /* Send the character */
  454.         }
  455.         write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  456.  
  457.         /* End of frame. Wait for TxEOM to go high, indicating start of
  458.          * CRC transmission. Note that we don't reset the transmit
  459.          * interrupt pending flag as one ordinarily would, since we're
  460.          * not using tx interrupts.
  461.          */
  462.         while(!(inportb(ctl) & TxEOM))
  463.             ;
  464.  
  465.         free(buffer);
  466.     }
  467. }
  468.  
  469. /* Turn on high speed transmitter. Does p-persistence, then sends a dummy
  470.  * frame to allow for keyup delay. Returns with transmitter on and interrupts
  471.  * disabled
  472.  */
  473. static void
  474. hstxon(hp)
  475. struct hdlc *hp;
  476. {
  477.     int16 ctl,data;
  478.     int i;
  479.  
  480.     ctl = hp->ctl;
  481.     data = hp->data;
  482.  
  483.     /* P-persistence. The slot time is fixed at one tick. */
  484.     while((rand() & 0xff) > uchar(hp->p))
  485.         pause(1L);
  486.  
  487.     /* Prevent distractions. In particular, block off the DCD interrupt
  488.      * so we don't hear our own carrier and hang in the interrupt handler!
  489.      * Note that simply disabling CPU interrupts isn't enough since
  490.      * the call to pause will block and the kernel will re-enable
  491.      * them.
  492.      */
  493.     write_scc(ctl,R9,0);    /* Disable all SCC interrupts */
  494.     (void)dirps();        /* Return value is always 1 */
  495.  
  496.     /* Turn on carrier, enable transmitter */
  497.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  498.  
  499.     /* Delay by sending dummy frame */
  500.     for(i=hp->txdelay;i != 0;i--){
  501.         while(!(inportb(ctl) & Tx_BUF_EMP))
  502.             ;
  503.         outportb(data,0);
  504.     }
  505.     write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  506.  
  507.     /* End of frame. Wait for TxEOM to go high, indicating start of
  508.      * CRC transmission. Note that we don't reset the transmit interrupt
  509.      * pending flag as one ordinarily would, since we're not using tx
  510.      * interrupts.
  511.      */
  512.     while(!(inportb(ctl) & TxEOM))
  513.         ;
  514. }
  515. /* Turn transmitter off at the end of a series of frames */
  516. static void
  517. hstxoff(hp)
  518. struct hdlc *hp;
  519. {
  520.     int cnt;
  521.     int16 ctl,data;
  522.  
  523.     ctl = hp->ctl;
  524.     data = hp->data;
  525.     /* To allow the SCC buffering to drain, we begin a dummy frame,
  526.      * then abort it
  527.      */
  528.     for(cnt=5;cnt != 0;cnt--){
  529.         while(!(inportb(ctl) & Tx_BUF_EMP))
  530.             ;
  531.         outportb(data,0);
  532.     }
  533.     write_scc(ctl,R0,SEND_ABORT);
  534.  
  535.     /* Turn off carrier and disable transmitter */
  536.     write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
  537.     /* Re-Enable SCC interrupts */
  538.     write_scc(ctl,R9,MIE|NV);        
  539.     restore(1);    /* Turn interrupts back on */
  540. }
  541.  
  542. int
  543. dohs(argc,argv,p)
  544. int argc;
  545. char *argv[];
  546. void *p;
  547. {
  548.     register int i;
  549.     register struct hdlc *hp;
  550.  
  551.     for(i=0;i<2*Nhs;i++){
  552.         hp = &Hdlc[i];
  553.         printf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
  554.             i,hp->txpkts,hp->exints,hp->good,hp->rxbytes,
  555.             hp->nomem,hp->toobig,hp->crcerr,hp->aborts,hp->overrun);
  556.     }
  557.     return 0;
  558. }
  559. #ifdef    notdef        /* replaced with assembler in 8530.asm */
  560. /* Read data from the 8530 receiver.
  561.  * Returns when either a good frame is received, or when carrier drops.
  562.  * If a good frame is received, the length is returned; otherwise -1.
  563.  */
  564. int
  565. rx8530(ctl,data,buf,bufsize)
  566. int16 ctl,data;
  567. char *buf;
  568. int16 bufsize;
  569. {
  570.     int cnt = 0;
  571.     register char status;
  572.     char error;
  573.     register char *cp = buf;
  574.  
  575.     for(;;){
  576.         status = inportb(ctl);
  577.         if(!(status & DCD)){
  578.             cnt = -1;
  579.             break;
  580.         } else if(status & BRK_ABRT){
  581.             cp = buf;
  582.             cnt = 0;
  583.         } else if(status & Rx_CH_AV){
  584.             /* Receive character is ready, get it */
  585.             *cp++ = inportb(data);
  586.             if(++cnt > bufsize){
  587.                 /* Buffer overflow, start again */
  588.                 write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  589.                 cp = buf;
  590.                 cnt = 0;
  591.             }
  592.         } else if((error = read_scc(ctl,R1)) & END_FR){
  593.             if(!(error & CRC_ERR))
  594.                 break;    /* Good frame! */
  595.             /* Bad frame, start again */
  596.             cp = buf;
  597.             cnt = 0;
  598.         }
  599.     }
  600.     return cnt;
  601. }
  602. #endif
  603.  
  604.